package com.itheima.stock.service.impl;

import com.google.common.base.Strings;
import com.itheima.stock.constant.ConstName;
import com.itheima.stock.mapper.SysUserMapper;
import com.itheima.stock.pojo.SysUser;
import com.itheima.stock.service.UserService;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.LoginRespVo;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public R<LoginRespVo> login(LoginReqVo vo) {
        if (vo==null || Strings.isNullOrEmpty(vo.getUsername())
                     || Strings.isNullOrEmpty(vo.getPassword())
                     || Strings.isNullOrEmpty(vo.getRkey())
                     || Strings.isNullOrEmpty(vo.getCode())){
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        //从程序执行的效率看，先进行校验码的校验，成本较低
        //补充：根据传入的rkye从redis中获取校验码
        String rCheckCode =(String) redisTemplate.opsForValue().get(ConstName.CHECK_PREFIX + vo.getRkey());
        if (rCheckCode==null || ! rCheckCode.equals(vo.getCode())) {
            //响应验证码输入错误
            return R.error(ResponseCode.SYSTEM_VERIFY_CODE_ERROR.getMessage());
        }
        //是否需要添加手动淘汰redis缓存的数据,如果想快速淘汰，则可手动删除
        redisTemplate.delete(ConstName.CHECK_PREFIX + vo.getRkey());
        //根据用户名查询用户信息
        SysUser user=this.sysUserMapper.findByUserName(vo.getUsername());
        //判断用户是否存在，存在则密码校验比对
        if (user==null || !passwordEncoder.matches(vo.getPassword(),user.getPassword())){
            return R.error(ResponseCode.SYSTEM_PASSWORD_ERROR.getMessage());
        }
        //组装登录成功数据
        LoginRespVo respVo = new LoginRespVo();
        //属性名称与类型必须相同，否则copy不到
        BeanUtils.copyProperties(user,respVo);
        return  R.ok(respVo);
    }

    @Override
    public R<Map> getCaptcha() {
        //1.生成4位数的随机校验码（仅仅是数字）
        String checkCode = RandomStringUtils.randomNumeric(4);
        //2.模拟session，生成sessinId 坑：前端js获取java中long类型的数据后，自动转int类型，但是long类型数据过长，会导致
        //前端转化时精度丢失
        long sessionId = idWorker.nextId();
        //最好为redis下保存的数据的key取一个业务前缀,方便数据的查看和后期的维护
        String rkey= ConstName.CHECK_PREFIX+sessionId;
        //3.将sessionid作为key，校验码作为value保存在redis下，并设置失效时间1分钟
        redisTemplate.opsForValue().set(rkey,checkCode,5, TimeUnit.MINUTES);
        //4.组装数据并响应
        Map info=new HashMap();
        info.put("code",checkCode);
        //小心！
        info.put("rkey",sessionId+"");
        return R.ok(info);
    }
}
